﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Threading.Tasks;
using Db8.Data;
using Db8.DataAccess;
using Db8.ViewModels;

namespace Db8.Controllers
{
    public class ClaimController : ControllerBase
    {
        private Db8Context db = new Db8Context();

        int PAGE_SIZE = 10;

        //
        // GET: /Claim/
        //[Authorize]
        public ActionResult Index(string filter)
        {
            if (Request.IsSupportedMobileDevice())
                return RedirectToAction("Index", "Mobile");

            if (filter != null)
            {
                if (filter.StartsWith("+"))
                    StickyFilter = filter;
                else
                    StickyFilter = "";
            } 
            else
            {
                if (StickyFilter != "")
                    return RedirectToAction("Index", new { filter = StickyFilter });
            }

            ViewBag.EnableEdit = false;
            List<ClaimViewModel> claims;
            if (string.IsNullOrEmpty(filter))
            {
                claims = db.ListClaims(0, PAGE_SIZE, false, true)
                    .Select(claim => ClaimViewModel.FromClaim(claim)).ToList();
            }
            else
            {
                claims = db.SearchClaims(filter, PAGE_SIZE, false, true)
                    .Select(claim => ClaimViewModel.FromClaim(claim)).ToList();
            }
            claims.ForEach(m => { m.Filter = filter; });

            ViewBag.TopKeywords = db.GetTopKeywords(StickyFilter);

            return View(claims);
        }

        public ActionResult Browse()
        {
            int count = 10;
            var model = new BrowseViewModel()
            {
                Popular = db.GetPopularKeywords(count),
                Recent = db.GetRecentKeywords(count)
            };
            return View(model);
        }

        //[Authorize]
        public ActionResult Keyword(string id)
        {
            ViewBag.EnableEdit = false;
            ViewBag.Keyword = id;

            List<ClaimViewModel> claims;
            if (string.IsNullOrEmpty(id))
            {
                claims = db.ListClaims(0, PAGE_SIZE, false, true)
                    .Select(claim => ClaimViewModel.FromClaim(claim)).ToList();
            }
            else
            {
                claims = db.ListClaims(id, 0, PAGE_SIZE, false, true)
                    .Select(claim => ClaimViewModel.FromClaim(claim)).ToList();
            }
            claims.ForEach(m => { m.Filter = id; });

            return View(claims);
        }

        //[Authorize]
        public ActionResult IndexMore(string keyword, int skip)
        {
            ViewBag.EnableEdit = false;
            List<ClaimViewModel> claims;
            if (string.IsNullOrEmpty(keyword))
            {
                claims = db.ListClaims(skip, PAGE_SIZE, false, true)
                    .Select(claim => ClaimViewModel.FromClaim(claim)).ToList();
                claims.ForEach(m => { m.Filter = keyword; });
            }
            else
            {
                claims = db.ListClaims(keyword, skip, PAGE_SIZE, false, true)
                    .Select(claim => ClaimViewModel.FromClaim(claim)).ToList();
                claims.ForEach(m => { m.Filter = keyword; });
            }

            ViewBag.TopKeywords = db.GetTopKeywords(StickyFilter);

            return PartialView("_IndexMore", claims);
        }


        //
        // GET: /Claim/Details/5
        //[Authorize]
        public ActionResult Details(int id, string filter)
        {
            ViewBag.EnableEdit = true;
            ClaimViewModel model = ClaimViewModel.FromClaim(db.GetClaimById(id));
            if (model == null)
            {
                return RedirectToAction("Index");
            }
            ViewBag.PageDescription = model.Claim.Statement;
            model.Filter = filter;
            return View(model);
        }

        // 
        // GET: /Claim/ViewPartial/5
        //[Authorize]
        public ActionResult ViewPartial(int id)
        {
            ViewBag.EnableEdit = true;
            ClaimViewModel model = ClaimViewModel.FromClaim(db.GetClaimById(id));
            if (model == null)
            {
                return PartialView("_ClaimView", new ClaimViewModel() { Claim = new Claim(), Keywords = "" });
            }

            return PartialView("_ClaimView", model);
        }


        //
        // GET: /Claim/ClaimNew
        [Authorize(Roles = "Content Administrator")]
        public ActionResult ClaimNew()
        {
            return PartialView("_ClaimNew");
        }

        //
        // GET: /Claim/CreateRoot?counterTarget={int}
        [Authorize(Roles = "Content Administrator")]
        public ActionResult CreateRoot(int counterTarget)
        {
            ViewData["counterTarget"] = counterTarget;
            ViewData["Keywords"] = StickyFilter;
            ViewBag.Subform = false;
            return View("Create", new Claim());
        }

        //
        // POST: /Claim/Create
        [HttpPost, Authorize(Roles = "Content Administrator")]
        public ActionResult CreateRoot(Claim claim, FormCollection collection)
        {
            if (claim.Statement == "Error")
            {
                string x = null;
                if (x.Length > 1)
                    return View();
            }

            if (ModelState.IsValid)
            {
                CreateData(claim, collection);

                // Get fresh view
                ViewBag.EnableEdit = true;
                ClaimViewModel model = ClaimViewModel.FromClaim(db.GetClaimById(claim.ClaimId));
                if (model == null)
                {
                    return RedirectToAction("Index");
                }
                return RedirectToAction("Details", "Claim", new { id = claim.ClaimId });
            }

            ViewData["counterTarget"] = 0;
            ViewBag.Subform = false;
            return View("Create");
        }

        //
        // GET: /Claim/Create?counterTarget={int}
        [Authorize(Roles = "Content Administrator")]
        public ActionResult Create(int counterTarget)
        {
            ViewData["counterTarget"] = counterTarget;
            ViewData["Keywords"] = StickyFilter;
            ViewBag.Subform = true;
            return PartialView("_ClaimCreate", new Claim());
        }

        //
        // POST: /Claim/Create
        [HttpPost, Authorize(Roles = "Content Administrator")]
        public ActionResult Create(Claim claim, FormCollection collection)
        {
            if (ModelState.IsValid)
            {
                CreateData(claim, collection);

                // Get fresh view
                ViewBag.EnableEdit = true;
                ClaimViewModel model = ClaimViewModel.FromClaim(db.GetClaimById(claim.ClaimId));
                if (model == null)
                {
                    return PartialView("_ClaimNew");
                }
                return PartialView("_ClaimView", model);
            }

            return PartialView("_ClaimNew");
        }

        [Authorize(Roles = "Content Administrator")]
        void CreateData(Claim claim, FormCollection collection)
        {
            Data.User user = (Data.User)User;
            claim.CreatedBy = user.UserId;
            claim.CreatedDt = DateTime.UtcNow;
            claim.ModifiedBy = user.UserId;
            claim.ModifiedDt = DateTime.UtcNow;
            if (claim.Abstract == null)
                claim.Abstract = "";
            db.Claims.Add(claim);

            int counterTarget = 0;
            if (!string.IsNullOrEmpty(collection["counterTarget"]))
            {
                counterTarget = int.Parse(collection["counterTarget"]);
            }

            if (counterTarget != 0)
            {
                CounterClaim cc = new CounterClaim()
                {
                    Claim = claim,
                    TargetClaimId = counterTarget
                };
                db.CounterClaims.Add(cc);
            }

            string keywords = collection["Keywords"];
            string[] newKeywords = keywords.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()).ToArray();
            List<Keyword> keywordsToAdd = db.Keywords.Where(kw => newKeywords.Any(k => k == kw.Value)).ToList();
            foreach (string keywordToAdd in newKeywords)
            {
                Keyword toAdd = keywordsToAdd.Where(kw => string.Compare(kw.Value,keywordToAdd, true) == 0).FirstOrDefault();
                if (toAdd != null)
                {
                    // already exists:

                    // add relationship
                    ClaimKeyword claimKeyword = new ClaimKeyword()
                    {
                        Claim = claim,
                        Keyword = toAdd
                    };
                    db.ClaimKeywords.Add(claimKeyword);

                    // increment counter
                    toAdd.ClaimCount = toAdd.ClaimCount + 1;
                    db.Entry(toAdd).State = EntityState.Modified;
                }
                else
                {
                    // create new keyword
                    toAdd = new Keyword()
                    {
                        Value = keywordToAdd,
                        ClaimCount = 1
                    };
                    db.Keywords.Add(toAdd);

                    // add relationship
                    ClaimKeyword claimKeyword = new ClaimKeyword()
                    {
                        Claim = claim,
                        Keyword = toAdd
                    };
                    db.ClaimKeywords.Add(claimKeyword);
                }
            }
            db.SaveChanges();
        }

        // 
        // GET /Claim/Edit

        [Authorize(Roles = "Content Administrator")]
        public ActionResult Edit(int id)
        {
            ClaimViewModel model = ClaimViewModel.FromClaim(db.GetClaimById(id));
            if (model == null)
            {
                return RedirectToAction("Index");
            }
            // can't get a hydrated object into Post Edit, so reverting to what works...
            ViewData["Keywords"] = model.Keywords;
            return PartialView("_ClaimEdit", model.Claim);
        }

        //
        // POST: /Claim/Edit/5
        [ValidateInput(false), HttpPost, Authorize(Roles = "Content Administrator")]
        public ActionResult Edit(Claim claim, FormCollection collection)
        {
            if (ModelState.IsValid)
            {
                var existing = db.Claims.Where(c => c.ClaimId == claim.ClaimId).FirstOrDefault();
                db.Entry(existing).State = EntityState.Modified;
                Data.User user = (Data.User)User;
                existing.ModifiedBy = user.UserId;
                existing.ModifiedDt = DateTime.UtcNow;

                existing.Statement = claim.Statement;
                existing.Abstract = claim.Abstract;
                if (existing.Abstract == null)
                    existing.Abstract = "";

                string keywords = collection["Keywords"];

                List<ClaimKeyword> claimKeywords = db.ClaimKeywords.Where(ck => claim.ClaimId == ck.ClaimId).ToList();

                string[] newKeywords = keywords.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()).ToArray();
                string[] oldKeywords = claimKeywords.Select(ck => ck.Keyword.Value).ToArray();
                string[] keywordsToAdd = newKeywords.Except(oldKeywords).ToArray();
                string[] keywordsToRemove = oldKeywords.Except(newKeywords).ToArray();
                List<Keyword> keywordsToAddOrRemoved = db.Keywords.Where(kw => keywordsToAdd.Any(k => k == kw.Value) || keywordsToRemove.Any(k => k == kw.Value)).ToList();
                foreach (string keywordToAdd in keywordsToAdd)
                {
                    Keyword toAdd = keywordsToAddOrRemoved.Where(kw => string.Compare(kw.Value,keywordToAdd, true) == 0).FirstOrDefault();
                    if (toAdd != null)
                    {
                        // already exists:
                            
                        // add relationship
                        ClaimKeyword claimKeyword = new ClaimKeyword()
                        {
                            Claim = existing,
                            Keyword = toAdd
                        };
                        db.ClaimKeywords.Add(claimKeyword);

                        // increment counter
                        toAdd.ClaimCount = toAdd.ClaimCount + 1;
                        db.Entry(toAdd).State = EntityState.Modified;
                    }
                    else
                    {
                        // create new keyword
                        toAdd = new Keyword()
                        {
                            Value = keywordToAdd,
                            ClaimCount = 1
                        };
                        db.Keywords.Add(toAdd);

                        // add relationship
                        ClaimKeyword claimKeyword = new ClaimKeyword()
                        {
                            Claim = existing,
                            Keyword = toAdd
                        };
                        db.ClaimKeywords.Add(claimKeyword);
                    }
                }

                List<ClaimKeyword> claimKeywordsToRemove = db.ClaimKeywords.Include("Keyword").Where(ck => keywordsToRemove.Any(kr => kr == ck.Keyword.Value)).ToList();
                foreach (var keywordToRemove in claimKeywordsToRemove)
                {
                    // remove relationship
                    Keyword toRemove = keywordToRemove.Keyword; //keywordsToAddOrRemoved.Where(kw => kw.Value == keywordToRemove).FirstOrDefault();
                    db.ClaimKeywords.Remove(keywordToRemove);

                    // decrement counter
                    toRemove.ClaimCount = toRemove.ClaimCount - 1;
                    db.Entry(toRemove).State = EntityState.Modified;
                }
                db.SaveChanges();

                // Get fresh view
                ViewBag.EnableEdit = true;
                ClaimViewModel model = ClaimViewModel.FromClaim(db.GetClaimById(existing.ClaimId));
                if (model == null)
                {
                    return RedirectToAction("Index");
                }
                return PartialView("_ClaimView", model);
            }

            // differentiate?
            ViewBag.EnableEdit = true;
            return PartialView("_ClaimView", ClaimViewModel.FromClaim(claim));
        }

        //
        // GET: /Claim/Delete/5
        [Authorize(Roles = "Content Administrator")]
        public ActionResult Delete(int id)
        {
            ViewBag.EnableEdit = true;
            ClaimViewModel model = ClaimViewModel.FromClaim(db.GetClaimById(id));
            if (model == null)
            {
                return RedirectToAction("Index");
            }

            return PartialView("_ClaimDelete", model);
        }

        //
        // POST: /Claim/Delete/5
        [HttpPost, Authorize(Roles = "Content Administrator"), ActionName("Delete")]
        public ActionResult DeleteConfirmed(int id)
        {            
            Claim claim = db.Claims
                .Include("ClaimKeywords")
                .Include("ClaimKeywords.Keyword")
                .Include("CounteredClaims")
                .Include("CounteredClaims.TargetClaim")
                .Where(c => c.ClaimId == id).FirstOrDefault();

            //UserActivity activity = new UserActivity((Data.User)User, "Delete", "Claim", id.ToString());
            //if (claim.CounteredClaims.Count() > 0)
            //{
            //    activity.Url = "/Claim/Details/" + claim.CounteredClaims.First().TargetClaim.ClaimId;
            //}
            //activity.Before = claim.Statement + "<br />";

            foreach (ClaimKeyword ck in claim.ClaimKeywords.ToArray())
            {
                ck.Keyword.ClaimCount = ck.Keyword.ClaimCount - 1;
                db.Entry(ck.Keyword).State = EntityState.Modified;
                db.ClaimKeywords.Remove(ck);
            }
            foreach (CounterClaim cc in claim.CounteredClaims.ToArray())
            {
                db.CounterClaims.Remove(cc);
            }
            foreach (SupportingClaim sc in claim.SupportedClaims.ToArray())
            {
                db.SupportingClaims.Remove(sc);
            }
            db.Claims.Remove(claim);
            db.SaveChanges();
            return PartialView("_ClaimNew");
        }

        //[Authorize(Roles = "Content Administrator")]
        [Authorize()]
        public ActionResult Community()
        {
            return View(db.Users.OrderByDescending(u => u.LastActivityDt).ToList());
        }

        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }

    }
}